home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Chans / smtp / smtpsrvr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  22.8 KB  |  1,122 lines

  1. /* smtpsrvr.c: server for smtp requests */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/smtp/RCS/smtpsrvr.c,v 6.0 1991/12/18 20:12:19 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/smtp/RCS/smtpsrvr.c,v 6.0 1991/12/18 20:12:19 jpo Rel $
  9.  *
  10.  * $Log: smtpsrvr.c,v $
  11.  * Revision 6.0  1991/12/18  20:12:19  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "head.h"
  19. #include "prm.h"
  20. #include "q.h"
  21. #include "dl.h"
  22. #include <isode/cmd_srch.h>
  23. #include <signal.h>
  24. #include <sys/stat.h>
  25. #include <isode/internet.h>
  26. #include <errno.h>
  27.  
  28.  
  29.  
  30. /* -- external variables -- */
  31.  
  32. extern char *hdr_822_bp, *ia5_bp;
  33. extern char        *ctime(),
  34.             *quedfldir,
  35.             *postmaster,
  36.             *pptailor,
  37.             *getpostmaster();
  38. extern time_t        time();
  39. extern    ADDR        *adr_new ();
  40.  
  41. #if sparc && defined(__GNUC__)    /* work around bug in gcc 1.37 sparc version */
  42. #define inet_ntoa myinet_ntoa
  43.  
  44. static char *myinet_ntoa (in)
  45. struct in_addr in;
  46. {
  47.     static char buf[80];
  48.  
  49.     (void) sprintf (buf, "%d.%d.%d.%d",
  50.             (in.s_addr >> 24) & 0xff,
  51.             (in.s_addr >> 16) & 0xff,
  52.             (in.s_addr >> 8 ) & 0xff,
  53.             (in.s_addr    ) & 0xff);
  54.     return buf;
  55. }
  56. #else
  57. extern char    *inet_ntoa ();
  58. #endif
  59.  
  60.  
  61.  
  62. /* -- internal definitions -- */
  63.  
  64. #define BUFL        8096    /* -- length of buf -- */
  65. #define CNULL        '\0'    /* -- null -- */
  66. #define CR        '\r'    /* -- carriage return -- */
  67. #define LF        '\n'    /* -- line feed -- */
  68. #define NTIMEOUT    300    /* -- 5 minute timeout on net I/O -- */
  69.  
  70.  
  71.  
  72. /* -- internal variables -- */
  73.  
  74. static    char
  75.     buf [BUFL],        /* -- for general usage -- */
  76.     *getline(),
  77.     netbuf [BUFL],        /* -- contains the valid characters -- */
  78.     *adrfix(),
  79.     *arg,            /* -- 0 if no arg - pts to comm param -- */
  80.     *channel = "smtp",
  81.     *netptr = netbuf,    /* -- next char to come out of netbuf -- */
  82.     *progname,
  83.     *sender = NULLCP,
  84.     *them,
  85.     *realthem,
  86.     *us;
  87.  
  88. static    int
  89.     hellod = 0,
  90.     nstimeout = 30,
  91.     dont_mung = 0,        /* -- used by getline() to limit munging -- */
  92.     net_count = 0,        /* -- no of valid characters in netbuf -- */
  93.     no_recip = 0;        /* -- no of valid recipients accepted -- */
  94.  
  95. CHAN    *chanptr,
  96.     *ch_nm2struct();
  97.  
  98. extern CMD_TABLE    qtbl_con_type[];
  99.  
  100. static void byebye (), pprestart (), ppbegin (), ppstart (),
  101.     netreply (), rset ();
  102.  
  103. static void initialise (), dispatch ();
  104. static char *official ();
  105.  
  106.  
  107.  
  108. /* --------------------------------------------------------------
  109.  .                                .
  110.  .    C o m m a n d    D i s p a t c h      T a b l e        .
  111.  .                                .
  112.  * ------------------------------------------------------------ */
  113.  
  114. static void data (), helo (), help (), mail (), confirm (),
  115.     quit (), rcpt (), vrfy (), expn ();
  116.  
  117. static struct comarr   /* -- the command table -- */
  118. {
  119.     char        *cmdname;        /* -- ascii name -- */
  120.     void        (*cmdfunc)();        /* -- cmd func to call -- */
  121. } commands [] = {
  122.     "data",        data,
  123.     "helo",        helo,
  124.     "help",        help,
  125.     "mail",        mail,
  126.     "noop",        confirm,
  127.     "quit",        quit,
  128.     "rcpt",        rcpt,
  129.     "rset",        rset,
  130.     "vrfy",        vrfy,
  131.     "expn",        expn,
  132.     NULLCP,        NULL
  133. };
  134.  
  135. static char usage[] = "Usage: smtp [-t timeout] [-T tailor] channel";
  136.  
  137. main (argc, argv)
  138. int    argc;
  139. char    **argv;
  140. {
  141.     char    replybuf [BUFSIZ];
  142.     char    *cp;
  143.         int    isnumeric;
  144.     int    opt;
  145.     extern char *optarg;
  146.     extern int optind;
  147.  
  148.     progname = argv [0];
  149.  
  150.     (void) signal (SIGQUIT,SIG_IGN);
  151.     (void) signal (SIGTERM,quit);
  152.  
  153.     while ((opt = getopt (argc, argv, "t:T:")) != EOF) {
  154.         switch (opt) {
  155.             case 't':
  156.             nstimeout = atoi (optarg);
  157.             break;
  158.  
  159.             case 'T':
  160.             pptailor = optarg;
  161.             break;
  162.  
  163.             default:
  164.             sys_init (progname);
  165.             fprintf (stderr, "bad switch -%c: %s\n", opt, usage);
  166.             PP_OPER (NULLCP, ("Bad argument -%c: %s", opt, usage));
  167.             exit (1);
  168.         }
  169.     }
  170.     
  171.     argc -= optind;
  172.     argv += optind;
  173.  
  174. #ifdef  NAMESERVER
  175.         ns_settimeo (nstimeout); /* don't wait forever! */
  176. #endif
  177.  
  178.     if (argc != 1) {
  179.         sys_init (progname);
  180.         PP_OPER (NULLCP, ("smtpsrvr - no channel given!"));
  181.         exit (NOTOK);
  182.     }
  183.     channel = *argv;
  184.     sys_init (channel);
  185.     (void) chdir (quedfldir);
  186.  
  187.  
  188.     initialise ();        /* fill in us & them */
  189.     /* SEK - force validation of IP address */
  190.  
  191.         for (isnumeric = TRUE, cp=them; *cp++ != '\0';) 
  192.         if (!isdigit(*cp) && *cp != '.' && *cp != '\0') {
  193.             isnumeric = FALSE;
  194.             break;
  195.         }
  196.  
  197.     /* -- find out who you are I might even believe you. -- */
  198.  
  199.     if ((chanptr = ch_mta2struct (channel, them)) == NULLCHAN) {
  200.         PP_LOG (LLOG_EXCEPTIONS, 
  201.             ("unknown channel: %s", channel));
  202.         (void) sprintf (replybuf,
  203.                 "421 %s: channel '%s' is unknown to PP. (Complain to:  %s)\r\n",
  204.                 us, channel, postmaster);
  205.         netreply (replybuf);
  206.         exit (NOTOK);
  207.     }
  208.  
  209.     if (isnumeric && 
  210.          lexequ (chanptr -> ch_in_info, "sloppy") != 0) {
  211.         PP_OPER (NULLCP, ("can't resolve '%s'", them));
  212.         (void) sprintf (replybuf,
  213.             "421 %s: PP cannot resolve your address. '%s' (Help from:  %s)\r\n",
  214.             us, them, postmaster);
  215.         netreply (replybuf);
  216.         exit (NOTOK);
  217.     }
  218.       
  219.     
  220.     channel = chanptr -> ch_name;
  221.     rename_log (channel);
  222.  
  223.     PP_NOTICE (("Connection from %s channel %s", realthem, channel));
  224.  
  225.     ppbegin ();
  226.  
  227.     /* -- say we're listening -- */
  228.  
  229.     (void) sprintf (replybuf,
  230.             "220 %s PP Here - Pleased to meet you (Complaints/bugs to:  %s)\r\n",
  231.             us, postmaster);
  232.     netreply (replybuf);
  233.  
  234.     while (cp = getline()) {
  235.         PP_LOG (LLOG_PDUS, ("<- %s", buf));
  236.  
  237.         dispatch (buf);
  238.     }
  239.     byebye (net_count < 0 ? 1 : 0);
  240. }
  241.  
  242.  
  243. /* ---------------------  Static  Routines  ------------------------------- */
  244.  
  245. static void dispatch (str)
  246. char    *str;
  247. {
  248.     register struct comarr    *comp;
  249.  
  250.     for (comp = commands;comp->cmdname != NULL; comp ++) {
  251.         if (strcmp (str, comp->cmdname) == 0) {
  252.             (*comp->cmdfunc)(); /* call comm proc */
  253.             return;
  254.         }
  255.     }
  256.     PP_LOG (LLOG_EXCEPTIONS, ("Unknown command: %s", buf));
  257.     netreply ("500 Unknown or unimplemented command\r\n");
  258. }
  259.  
  260. static void initialise ()
  261. {
  262. #ifdef NAMESERVER
  263.     int i;
  264. #endif
  265.     char    workarea[BUFSIZ];
  266.     struct sockaddr_in    rmtaddr;
  267.     int len;
  268.     struct hostent *hp;
  269.  
  270.     if (gethostname (workarea,  sizeof workarea) == -1)
  271.         PP_SLOG (LLOG_EXCEPTIONS, "gethostname",
  272.              ("Can't find out who I am"));
  273.  
  274.     us = official (workarea);
  275.         if(us == NULLCP) {
  276.         PP_OPER (NULLCP, 
  277.              ("Cannot find 'official' name of host '%s'\n",
  278.               workarea));
  279.                 exit(-1);
  280.         }
  281.  
  282.     len = sizeof rmtaddr;
  283.     if (getpeername (0, (struct sockaddr *)&rmtaddr, &len) != 0) {
  284.         PP_SLOG (LLOG_EXCEPTIONS, "getpeername", ("Can't figure out who called us"));
  285.         exit (-1);
  286.     }
  287. #ifdef NAMESERVER
  288.     for (i = 0 ; i < 4 ; i++) {
  289.         hp = gethostbyaddr((char *)&rmtaddr.sin_addr,
  290.                    sizeof(rmtaddr.sin_addr), AF_INET);
  291.         if(hp != NULL)
  292.             break;
  293.     }
  294. #else
  295.     hp = gethostbyaddr((char *)&rmtaddr.sin_addr,
  296.                sizeof(rmtaddr.sin_addr), AF_INET);
  297. #endif
  298.     if (hp == NULL) {
  299.         (void) strcpy(workarea, inet_ntoa(rmtaddr.sin_addr));
  300.         them = strdup (workarea);
  301.  
  302.         PP_LOG (LLOG_EXCEPTIONS,
  303.             ("lookup failed for address '%s'", workarea));
  304.     } else
  305.         them = strdup (hp->h_name);
  306.     realthem = them;
  307.     (void) signal (SIGPIPE, SIG_IGN);
  308. }    
  309.  
  310. /*
  311. name:        getline()
  312.  
  313. function:
  314.         - get commands from the standard input terminated by <cr><lf>.
  315.         - afix a pointer (arg) to any arguments passed.
  316.         - ignore carriage returns.
  317.         - map UPPER case to lower case.
  318.         - manage the netptr and net_count variables.
  319.  
  320. algorithm:
  321.         while we havent received a line feed and buffer not full
  322.  
  323.             if net_count is zero or less
  324.                 get more data from net
  325.                     error: return 0
  326.             check for delimiter character
  327.                 null terminate first string
  328.                 set arg pointer to next character
  329.             check for carriage return
  330.                 ignore it
  331.             if looking at command name
  332.                 convert upper case to lower case
  333.  
  334.         if command line (not mail)
  335.             null terminate last token
  336.         manage netptr
  337.  
  338. returns:
  339.         0 for EOF
  340.         -1 when an error occurs on network connection
  341.         ptr to last character (null) in command line
  342.  
  343.  
  344. variables:
  345.         dont_mung
  346.         net_count
  347.         netptr
  348.         buf
  349.  
  350.  
  351. --------------------------------------------------------------------------- */
  352.  
  353. static char *getline()
  354. {
  355.     register char    *inp;        /* -- input pointer in netbuf -- */
  356.     static char *outp;   /* -- output pointer in buf -- */
  357.     register int    c;        /* -- temporary char -- */
  358.  
  359.  
  360.     inp    = netptr;
  361.     outp    = buf;
  362.     arg    = NULLCP;
  363.  
  364.     do {
  365.         if (--net_count <= 0) {
  366.             if (timeout (NTIMEOUT)) {
  367.                 PP_SLOG (LLOG_EXCEPTIONS, "read",
  368.                      ("%s net input", realthem));
  369.                 return (NULLCP);
  370.             }
  371.  
  372.             net_count = read (0, netbuf, sizeof netbuf);
  373.             timeout (0);
  374.  
  375.             if (net_count == 0)     /* -- EOF -- */
  376.                 return NULLCP;
  377.             if (net_count < 0) {     /* -- error -- */
  378.                 PP_SLOG (LLOG_EXCEPTIONS, "read",
  379.                      ("%s net input", realthem));
  380.                 return NULLCP;
  381.             }
  382.             inp = netbuf;
  383.         }
  384.  
  385.         c = *inp++ & 0377;
  386.  
  387.         if (c == '\r')        /* -- ignore CR -- */
  388.             continue;    /* -- try to sneak through -- */
  389. #ifdef TELNET_SMTP
  390.         if (c >= 0200)        /* skip telnet codes */
  391.             continue;
  392. #endif
  393.  
  394.  
  395.         if (dont_mung == 0 && arg == NULL) {
  396.             /* -- if char is a delim afix token -- */
  397.  
  398.             if (c == ' ' || c == ',') {
  399.                 c = CNULL;    /* -- make null term'ed -- */
  400.                 arg = outp + 1; /* -- set arg ptr -- */
  401.             }
  402.             else if (isupper (c))
  403.                 /* -- do case mapping (UPPER -> lower) -- */
  404.                 c = tolower(c);
  405.         }
  406.  
  407.         *outp++ = c;
  408.  
  409.     }  while (c != '\n' && outp < &buf [BUFL]);
  410.  
  411.  
  412.     if (dont_mung == 0)
  413.         *--outp = 0;    /* -- null term the last token -- */
  414.  
  415.     /* -- scan off blanks in argument -- */
  416.     if (arg) {
  417.         while (*arg == ' ')
  418.             arg++;
  419.         if (*arg == '\0')
  420.             arg = 0;    /* -- if all blanks, no argument -- */
  421.     }
  422.  
  423.     if (dont_mung == 0)
  424.         PP_DBG (("'%s', '%s'",
  425.             buf, arg == 0 ? "<noarg>" : arg));
  426.  
  427.     /* -- reset netptr for next trip in -- */
  428.     netptr = inp;
  429.  
  430.     /* -- return success -- */
  431.     return (outp);
  432. }
  433.  
  434.  
  435.  
  436. /*
  437. The helo command
  438. */
  439.  
  440. static void helo()
  441. {
  442.     char    replybuf [BUFSIZ];
  443.     char    *cp;
  444.  
  445.     if (arg == NULLCP || *arg == 0) {
  446.         PP_LOG (LLOG_EXCEPTIONS, ("No argument to HELO"));
  447.         netreply ("501 No argument to HELO\r\n");
  448.         return;
  449.     }
  450.     (void) compress (arg, arg);
  451.     for (cp = arg; *cp; cp++) {
  452.         switch (*cp) {
  453.             case '\\':
  454.             cp++;
  455.             break;
  456.             case '[':
  457.             while (*cp && *cp != ']')
  458.                 cp ++;
  459.             break;
  460.  
  461.             default:
  462.             if (isascii(*cp) && (!iscntrl(*cp) && !isspace (*cp)))
  463.                 break;
  464.             /* fall */
  465.             case '(':
  466.             case ')':
  467.             case '<':
  468.             case '>':
  469.             case '@':
  470.             case ',':
  471.             case ';':
  472.             case ':':
  473.             case '"':
  474.             PP_LOG (LLOG_EXCEPTIONS,
  475.                 ("Bad character '%c' in domain name '%s'",
  476.                  *cp, arg));
  477.             netreply ("501 Bad hostname in HELO.\r\n");
  478.             return;
  479.         }
  480.     }
  481.  
  482.     hellod ++;
  483.     if (lexequ (arg, them) != 0) {
  484.         (void) sprintf (replybuf,
  485.                 "250 %s: You are bluffing - `%s` expected\r\n", 
  486.                     us, them);
  487.         PP_NOTICE (("%s claims to be %s", realthem, arg));
  488.     }
  489.     else
  490.         (void) sprintf (replybuf, "250 %s: Looks good to me\r\n", us);
  491.  
  492.     netreply (replybuf);
  493. }
  494.  
  495.  
  496.  
  497. /*
  498. handle the MAIL command     ("MAIL from:<user@host>")
  499. */
  500.  
  501. static void mail()
  502. {
  503.     static Q_struct qstruct;
  504.     Q_struct    *qp = &qstruct;
  505.     ADDR        *ap;
  506.     char        replybuf [BUFSIZ];
  507.     RP_Buf        thereply;
  508.     LIST_BPT    *new;    
  509.  
  510.     if (hellod == 0) {
  511.         PP_LOG (LLOG_EXCEPTIONS,
  512.             ("Expecting a HELO command"));
  513.         hellod ++; /* MH < 6.7 breaks this! */
  514.     }
  515.  
  516.     if (arg == 0 || *arg == 0) {
  517.         PP_LOG (LLOG_EXCEPTIONS,
  518.             ("No argument to MAIL supplied"));
  519.         netreply ("501 No argument supplied\r\n");
  520.         return;
  521.     }
  522.     else if (sender) {
  523.         PP_LOG (LLOG_EXCEPTIONS,
  524.             ("MAIL command already supplied"));
  525.         netreply ("503 MAIL command already accepted\r\n");
  526.         return;
  527.     }
  528.     else if (!prefix ("from:", arg)) {
  529.         PP_LOG (LLOG_EXCEPTIONS,
  530.             ("No sender given in MAIL"));
  531.         netreply ("501 No sender named\r\n");
  532.         return;
  533.     }
  534.  
  535.     /* -- Scan FROM: parts of arg -- */
  536.  
  537.     sender = index (arg, ':') + 1;
  538.     sender = adrfix (sender);
  539.  
  540.     q_init (qp);
  541.     new = list_bpt_new (hdr_822_bp); 
  542.     list_bpt_add (&qp -> encodedinfo.eit_types, new); 
  543.     new = list_bpt_new (ia5_bp); 
  544.     list_bpt_add (&qp -> encodedinfo.eit_types, new);
  545.     qp -> inbound = list_rchan_new (them, channel);
  546.  
  547.     ppstart ();
  548.  
  549.     if (rp_isbad (io_wrq (qp, &thereply))) {
  550.         PP_LOG (LLOG_EXCEPTIONS,
  551.             ("Can't write Q struct %s", thereply.rp_line));    
  552.         netreply ("451 Temporary problem initialising\r\n");
  553.         pprestart ();
  554.         return;
  555.     }
  556.  
  557.     if (sender == NULLCP || *sender == NULL)
  558.         sender = getpostmaster(AD_822_TYPE);
  559.  
  560.     PP_NOTICE (("Sender %s", sender));
  561.  
  562.     ap = adr_new (sender, AD_822_TYPE, 0);
  563.  
  564.     (void) io_wadr (ap, AD_ORIGINATOR, &thereply);
  565.     adr_tfree (ap);
  566.  
  567.     switch (thereply.rp_val) {
  568.         case RP_BHST:
  569.             thereply.rp_val = RP_NDEL;
  570.             break;    
  571.     }
  572.     if (rp_gbval (thereply.rp_val) == RP_BNO) {
  573.         PP_LOG (LLOG_EXCEPTIONS,
  574.             ("Can't write sender address %s [PERM]",
  575.              thereply.rp_line));
  576.         (void) sprintf (replybuf, "501 %s\r\n", thereply.rp_line);
  577.         netreply (replybuf);
  578.         pprestart();
  579.     }
  580.     else if (rp_gbval (thereply.rp_val) == RP_BTNO) {
  581.         PP_LOG (LLOG_EXCEPTIONS,
  582.             ("Can't write sender address %s [TEMP]",
  583.              thereply.rp_line));
  584.         (void) sprintf (replybuf, "451 %s\r\n", thereply.rp_line);
  585.         netreply (replybuf);
  586.         pprestart();
  587.     }
  588.     else
  589.         netreply ("250 OK\r\n");
  590.  
  591.     no_recip = 0;
  592. }
  593.  
  594.  
  595.  
  596. /*
  597. The RCPT command  ("RCPT TO:<forward-path>")
  598. */
  599.  
  600. static void rcpt()
  601. {
  602.     RP_Buf        thereply;
  603.     register char    *p;
  604.     char        replybuf [BUFSIZ];
  605.     ADDR        *ap;
  606.  
  607.     /* -- parse destination arg -- */
  608.  
  609.     if (hellod == 0) {
  610.         PP_LOG (LLOG_EXCEPTIONS,
  611.             ("Expecting a HELO command"));
  612.         hellod ++;    /* MH bug */
  613.     }
  614.  
  615.     if (sender == NULLCP) {
  616.         PP_LOG (LLOG_EXCEPTIONS, ("RCPT but no MAIL"));
  617.         netreply ("503 You must give a MAIL command first\r\n");
  618.         return;
  619.     }
  620.     else if (arg == NULLCP || !prefix ("to:", arg)) {
  621.         PP_LOG (LLOG_EXCEPTIONS, ("No recipient named in RCPT"));
  622.         netreply ("501 No recipient named.\r\n");
  623.         return;
  624.     }
  625.  
  626.     p = index (arg, ':') + 1;
  627.     p = adrfix (p);
  628.     if (p == NULLCP || *p == NULL) {
  629.         PP_LOG (LLOG_EXCEPTIONS, ("No recipient in RCPT"));
  630.         netreply ("501 No recipient named.\r\n");
  631.         return;
  632.     }
  633.  
  634.     PP_NOTICE (("Recipient Address '%s'", p));
  635.  
  636.  
  637.     ap = adr_new (p, AD_822_TYPE, no_recip + 1);
  638.  
  639.     (void) io_wadr (ap, AD_RECIPIENT, &thereply);
  640.  
  641.     adr_tfree (ap);
  642.  
  643.     if (thereply.rp_val == RP_BHST || 
  644.         rp_gbval (thereply.rp_val) == RP_BNO) {
  645.         PP_LOG (LLOG_EXCEPTIONS,
  646.             ("Problems writing address %s [PERM]",
  647.              thereply.rp_line));
  648.         (void) sprintf (replybuf, "550 %s\r\n",
  649.                 thereply.rp_line);
  650.         netreply (replybuf);
  651.     }
  652.     else if (rp_gbval (thereply.rp_val) == RP_BTNO) {
  653.         PP_LOG (LLOG_EXCEPTIONS,
  654.             ("Problems writing address %s [TEMP]",
  655.              thereply.rp_line));
  656.         (void) sprintf (replybuf, "451 %s\r\n",
  657.                 thereply.rp_line);
  658.         netreply (replybuf);
  659.     }
  660.     else {
  661.         netreply ("250 Recipient OK.\r\n");
  662.         no_recip++;
  663.     }
  664.  
  665. }
  666.  
  667.  
  668.  
  669. /*----------------------------------------------------------------------------
  670.  
  671.  
  672. ADDRFIX()  --  This function takes the SMTP "path" and removes the leading
  673. and trailing "<>"'s which would make the address illegal to RFC822 mailers.
  674. Note that although the specification states that the angle brackets are
  675. required, we will accept addresses  without them.   (DPK@BRL, 4 Jan 83)
  676.  
  677.  
  678. ----------------------------------------------------------------------------*/
  679.  
  680.  
  681. static char *adrfix (addrp)
  682. char            *addrp;
  683. {
  684.     register char    *cp;
  685.  
  686.  
  687.     PP_TRACE (("adrfix %s", addrp));
  688.     if (cp = index (addrp, '<')) {
  689.         addrp = ++cp;
  690.  
  691.         if (cp = rindex (addrp, '>'))
  692.             *cp = 0;
  693.     }
  694.  
  695.     (void) compress (addrp, addrp);
  696.  
  697.     PP_TRACE (("adrfix(): '%s'", addrp));
  698.  
  699.     return (addrp);
  700. }
  701.  
  702.  
  703. /*
  704. The DATA command.  Send text to Submit.
  705. */
  706.  
  707. static void data()
  708. {
  709.     char    tbuf[LINESIZE];
  710.     struct rp_bufstruct    thereply;
  711.     struct timeval data_time;
  712.     register char    *p,
  713.                 *bufptr;
  714.     int        errflg,
  715.                 werrflg,
  716.                 size = 0,
  717.                 doing_header = 1;
  718.  
  719.     errflg    = 0;
  720.     werrflg = 0;
  721.  
  722.     timer_start (&data_time);
  723.  
  724.     if (no_recip == 0) {
  725.         PP_LOG (LLOG_EXCEPTIONS, ("No recipients for DATA"));
  726.         netreply ("503 No recipients have been specified.\r\n");
  727.         return;
  728.     }
  729.  
  730.     if (rp_isbad (io_adend(&thereply))) {
  731.         PP_LOG (LLOG_EXCEPTIONS, 
  732.             ("Bad address end %s", thereply.rp_line));
  733.         netreply ("451 Unknown mail system trouble.\r\n");
  734.         return;
  735.     }
  736.  
  737.     if (rp_isbad (io_tinit (&thereply)) ||
  738.         rp_isbad (io_tpart (hdr_822_bp, FALSE, &thereply))) {
  739.         PP_LOG (LLOG_EXCEPTIONS, 
  740.             ("Bad text init %s", thereply.rp_line));
  741.         netreply ("451 Unknown text initialisation failure.\r\n");
  742.         return;
  743.     }
  744.  
  745.     netreply ("354 Enter Mail, end by a line with only '.'\r\n");
  746.  
  747.     dont_mung = 1;        /* -- tell getline only to drop cr -- */
  748.  
  749.  
  750.     PP_TRACE (("body of message"));
  751.  
  752.     while (1) {  /* -- forever -- */
  753.  
  754.         if ((p = getline()) == 0) {
  755.             p = "\n***Sender closed connection***\n";
  756.             errflg++;
  757.             break;
  758.         }
  759.  
  760.         if (p == (char *)NOTOK) {
  761.             p = "\n***Error on net connection***\n";
  762.             if (!errflg++)
  763.                 PP_LOG (LLOG_EXCEPTIONS,
  764.                     ("netread error from host %s",
  765.                     realthem));
  766.             break;
  767.         }
  768.  
  769.         /* -- are we done? -- */
  770.  
  771.         if (buf [0] == '.')
  772.             if (buf [1] == '\n')
  773.                 break;    /* -- yep -- */
  774.             else
  775.                 bufptr = &buf [1];  /* -- skip leading . -- */
  776.         else
  777.             bufptr = &buf [0];
  778.  
  779.         /* -- If write err occurs, stop writing but keep reading -- */
  780.  
  781.         if (!werrflg) {
  782.             size += p-bufptr;
  783.  
  784.             if (doing_header && buf [0] == '\n') {
  785.                 /*
  786.                   do we need to go convert into body parts ??
  787.                   */
  788.  
  789.                 doing_header = 0;
  790.  
  791.                 if (rp_isbad (io_tdend (&thereply))) {
  792.                     PP_LOG (LLOG_EXCEPTIONS,
  793.                         ("io_tdend - %s",
  794.                          thereply.rp_line));    
  795.                     netreply ("451 Data input problem.\r\n");
  796.                     return;
  797.                 }
  798.  
  799.                 (void) sprintf (tbuf, "1.%s", ia5_bp);
  800.                 if (rp_isbad (io_tpart (tbuf, FALSE, &thereply))) {
  801.                     PP_LOG (LLOG_EXCEPTIONS,
  802.                         ("io_tpart - %s",
  803.                          thereply.rp_line));    
  804.                     netreply ("451 Body input failure.\r\n");
  805.                     return;
  806.                 }
  807.             }
  808.             else if (rp_isbad (io_tdata (bufptr, (p-bufptr)))) {
  809.                 werrflg++;
  810.                 PP_LOG (LLOG_EXCEPTIONS, 
  811.                     ("error from submit"));
  812.             }
  813.  
  814.         }
  815.     }
  816.     if (doing_header) {
  817.         (void) sprintf (tbuf, "1.%s", ia5_bp);
  818.         if (rp_isbad (io_tdend (&thereply)) ||
  819.             rp_isbad (io_tpart (tbuf, FALSE, &thereply))) {
  820.             netreply ("451 Data Input problem.\r\n");
  821.             return;
  822.         }
  823.     }
  824.     dont_mung = 0;    /* -- set getline to normal operation -- */
  825.  
  826.     PP_TRACE (("Finished receiving text."));
  827.     timer_end (&data_time, size, "Data Received");
  828.  
  829.     if (werrflg) {
  830.         netreply ("451-Mail trouble (write error to mailsystem)\r\n");
  831.         netreply ("451 Please try again later.\r\n");
  832.         byebye (1);
  833.     }
  834.  
  835.     if (errflg)
  836.         byebye (1);
  837.  
  838.     if (rp_isbad (io_tdend (&thereply))) {
  839.         PP_LOG (LLOG_EXCEPTIONS, ("io_tdend - %s", thereply.rp_line));
  840.         netreply ("451 Data termination problems.\r\n");
  841.         return;
  842.     }
  843.  
  844.     (void) io_tend (&thereply);
  845.  
  846.     if (rp_isgood (rp_gval (thereply.rp_val))) {
  847.         (void) sprintf (buf, "250 %s\r\n", thereply.rp_line);
  848.         netreply (buf);
  849.     }
  850.     else if (rp_gbval (thereply.rp_val) == RP_BNO) {
  851.         PP_LOG (LLOG_EXCEPTIONS, 
  852.             ("io_tend failed %s", thereply.rp_line));
  853.         (void) sprintf (buf, "554 %s\r\n", thereply.rp_line);
  854.         netreply (buf);
  855.         return;
  856.     }
  857.     else {
  858.         PP_LOG (LLOG_EXCEPTIONS, 
  859.             ("io_tend failed %s", thereply.rp_line));
  860.         (void) sprintf (buf, "451 %s\r\n", thereply.rp_line);
  861.         netreply (buf);
  862.         return;
  863.     }
  864.  
  865.     PP_NOTICE (("<<< Message received from %s (%d recipients, %d bytes)",
  866.             realthem, no_recip, size));
  867.     sender = NULLCP;
  868.     no_recip = 0;
  869. }
  870.  
  871.  
  872.  
  873. /*
  874. The RSET command
  875. */
  876.  
  877. static void rset()
  878. {
  879.     pprestart ();
  880.     confirm();
  881. }
  882.  
  883. static void pprestart ()
  884. {
  885.     io_end (NOTOK);
  886.     ppbegin ();
  887. }
  888.  
  889. static void ppbegin ()
  890. {
  891.     RP_Buf reply;
  892.  
  893.     if (rp_isbad (io_init(&reply))) {
  894.         PP_LOG (LLOG_EXCEPTIONS,
  895.              ("can't reinitialize mail system [%s]",
  896.              reply.rp_line));
  897.         netreply ("421 Server can't initialize mail system (PP)\r\n");
  898.         byebye (2);
  899.     }
  900.     sender = NULLCP;
  901.     no_recip = 0;
  902. }
  903.  
  904. static void ppstart()
  905. {
  906.     RP_Buf reply;
  907.     struct prm_vars prm;
  908.  
  909.     prm_init (&prm);
  910.     if (rp_isbad (io_wprm (&prm, &reply))) {
  911.         PP_LOG (LLOG_EXCEPTIONS, ("can't set parameters [%s]",
  912.              reply.rp_line));
  913.         netreply ("421 Server can't initialize mail system (PP)\r\n");
  914.         byebye (2);
  915.     }
  916.  
  917.     no_recip = 0;
  918. }
  919.  
  920.  
  921.  
  922. /*
  923. The QUIT command
  924. */
  925.  
  926. static void quit()
  927. {
  928.     time_t    timenow;
  929.  
  930.     PP_NOTICE (("smtp server quit"));
  931.  
  932.     time (&timenow);
  933.  
  934.     (void) sprintf (buf, "221 %s says goodbye to %s at %.19s.\r\n",
  935.         us, them, ctime (&timenow));
  936.     netreply (buf);
  937.  
  938.     byebye (0);
  939. }
  940.  
  941.  
  942. static void byebye (retval)
  943. int retval;
  944. {
  945.     /*
  946.     if (retval == OK)
  947.         mm_sbend();
  948.     */
  949.     if (rp_isbad (retval))
  950.         PP_LOG (LLOG_EXCEPTIONS, ("Smtp server aborting"));
  951.  
  952.     io_end (retval == 0 ? OK : NOTOK);
  953.     exit (retval);
  954. }
  955.  
  956.  
  957. /*
  958. Reply that the current command has been logged and noted
  959. */
  960.  
  961. static void confirm()
  962. {
  963.     netreply ("250 OK\r\n");
  964. }
  965.  
  966.  
  967.  
  968. /*
  969. The help command gives a list of valid commands
  970. */
  971. static void help()
  972. {
  973.     register int        i;
  974.     register struct comarr    *p;
  975.     char            replybuf [BUFSIZ];
  976.  
  977.     netreply ("214-The following commands are accepted:\r\n214-");
  978.  
  979.     for (p=commands, i=1;  p->cmdname;  p++, i++) {
  980.         (void) sprintf (replybuf, "%s%s", p->cmdname,
  981.                 ((i%10)     ?  " "     :  "\r\n214-" ));
  982.         netreply (replybuf);
  983.     }
  984.  
  985.     (void) sprintf (replybuf, "\r\n214 Send complaints/bugs to: %s\r\n",
  986.             postmaster);
  987.     netreply (replybuf);
  988. }
  989.  
  990. /* vrfy - attempt to verify user is OK */
  991.  
  992. static void vrfy ()
  993. {
  994.     RP_Buf rp;
  995.     ADDR    *adr;
  996.     char buffer[BUFSIZ];
  997.     
  998.     if (hellod == 0) {
  999.         PP_LOG (LLOG_EXCEPTIONS,
  1000.             ("Expecting a HELO command"));
  1001.         hellod ++;        /* MH bug */
  1002.     }
  1003.  
  1004.     if (arg == NULLCP || *arg == 0) {
  1005.         PP_LOG (LLOG_EXCEPTIONS, ("No argument to VRFY command"));
  1006.         netreply ("501 No argument supplied\r\n");
  1007.         return;
  1008.     }
  1009.     adr = adr_new (arg, AD_822_TYPE, 1);
  1010.     if (rp_isbad (ad_parse (adr, &rp, CH_USA_PREF))) {
  1011.         PP_LOG (LLOG_EXCEPTIONS,
  1012.             ("Failed to VRFY '%s' [%s]", arg, rp.rp_line));
  1013.         (void) sprintf (buffer,
  1014.                 "550 User unknown [%s]\r\n",
  1015.                 rp.rp_line);
  1016.         netreply (buffer);
  1017.     }
  1018.     else {
  1019.         (void) sprintf (buffer, "250 <%s>\r\n",
  1020.                 adr -> ad_type == AD_822_TYPE ?
  1021.                 adr -> ad_r822adr : adr -> ad_r400adr);
  1022.         netreply (buffer);
  1023.     }
  1024.     adr_free (adr);
  1025. }
  1026.  
  1027. static void expn ()
  1028. {
  1029.     dl *list;
  1030.     Name    *np;
  1031.     struct stat statbuf;
  1032.     char    buffer[BUFSIZ];
  1033.  
  1034.     if (hellod == 0) {
  1035.         PP_LOG (LLOG_EXCEPTIONS,
  1036.             ("Expecting a HELO command"));
  1037.         hellod ++;    /* MH bug */
  1038.     }
  1039.  
  1040.     if (arg == NULLCP || *arg == 0) {
  1041.         PP_LOG (LLOG_EXCEPTIONS, ("No argument to VRFY command"));
  1042.         netreply ("501 No argument supplied\r\n");
  1043.         return;
  1044.     }
  1045.     switch (tb_getdl (arg, &list, OK)) {
  1046.         case DONE:
  1047.         if (list != NULL)
  1048.             dl_free(list);
  1049.         PP_NOTICE (("No such list %s", arg));
  1050.         netreply ("550 No such list\r\n");
  1051.         return;
  1052.  
  1053.         case NOTOK:
  1054.         if (list != NULL)
  1055.             dl_free(list);
  1056.         PP_LOG (LLOG_EXCEPTIONS, ("Error locating list %s", arg));
  1057.         netreply ("550 List Error\r\n");
  1058.         return;
  1059.     }
  1060.  
  1061.     if (list -> dl_file == NULLCP ||
  1062.         stat (list -> dl_file, &statbuf) == NOTOK ||
  1063.         (statbuf.st_mode & (~S_IFMT)) == SECRMODE) {
  1064.         netreply ("550 Access Denied to you\r\n");
  1065.         dl_free (list);
  1066.         return;
  1067.     }
  1068.  
  1069.     for (np = list -> dl_list; np; np = np -> next) {
  1070.         (void) sprintf (buffer, "250%c%s\r\n",
  1071.                 np -> next == NULL ? ' ' : '-',
  1072.                 np -> name);
  1073.         netreply (buffer);
  1074.     }
  1075.     dl_free (list);
  1076. }
  1077.         
  1078. /*
  1079. Send appropriate ascii responses over the network connection.
  1080. */
  1081.  
  1082. static void netreply (str)
  1083. char    *str;
  1084. {
  1085.     PP_LOG (LLOG_PDUS, ("-> %s", str));
  1086.  
  1087.     if (timeout (NTIMEOUT))
  1088.         byebye (1);
  1089.  
  1090.     if (write (1, str, strlen (str)) < 0) {
  1091.         timeout (0);
  1092.         PP_SLOG (LLOG_EXCEPTIONS, "write",
  1093.             ("(netreply) in writing [%s]", str));
  1094.         byebye (1);
  1095.     }
  1096.  
  1097.     timeout (0);
  1098.  
  1099.     PP_TRACE (("%s", str));
  1100. }
  1101.  
  1102. static char    *official (name)
  1103. char    *name;
  1104. {
  1105.     struct hostent *hp;
  1106. #ifdef NAMESERVER
  1107.     int    i;
  1108.  
  1109.         for(i = 0 ; i < 10 ; i++){
  1110.                 hp = gethostbyname(name);
  1111.                 if(hp != NULL)
  1112.                         break;
  1113.         PP_TRACE (("Timeout looking up %s", name));
  1114.                 if(i > 2)
  1115.                         sleep(i*2);
  1116.         }
  1117. #else
  1118.     hp = gethostbyname(name);
  1119. #endif
  1120.     return hp == NULL ? NULLCP : strdup (hp -> h_name);
  1121. }
  1122.